import { LoginService } from '~/service/login'
import { defineStore } from 'pinia'
import { IResource } from '~/types/sys/IResource'
import { IAuthInfo } from '~/types/sys/IAuthInfo'
import { MenuItem } from '~/types/ui/MenuItem'
import loginStore from '../loginStore'
import router from '~/router'
import { RouteRecordRaw } from 'vue-router'
import Empty from '~/views/main/Empty.vue'
import tabStore from './tab'

interface IUser {
  id: string
  userName: string
  displayName: string
}

interface IUserStore {
  user: IUser
  token: string
  roles: string[]
  resources: IResource[]
  inited: boolean
}

const menuTypes = {
  MENU: 'menu',
  DIRECTORY: 'directory',
  FUNCTION: 'function'
}

const menus: MenuItem[] = []

//获取到所有views下面的modules
const modules = import.meta.glob('~/views/**/*.vue')

const emptyLayout = import('~/views/main/Empty.vue')
const page404 = import('~/views/error/404.vue')

const genMenuTree = function (resources: IResource[]) {
  if (menus.length !== 0) return menus

  const resList = resources.filter((d) => d.resType === menuTypes.MENU || d.resType === menuTypes.DIRECTORY)
  let tops = resList.filter((t) => t.parentResId === undefined).sort((a, b) => a.sort - b.sort)

  const dynamicRouters: RouteRecordRaw[] = []

  const getDynamicComponent = (path: string) => {
    const fixPath = (path: string) => {
      const newPath = '/' + path
      return newPath === '/' ? '/' : newPath.replace(/\/\//g, '/').replace(/\/$/, '')
    }

    try {
      return modules[/* @vite-ignore */ `../../views${fixPath(path)}.vue`] || page404
    } catch (error) {
      return page404
    }
  }

  const mapRes2MenuItem = (res: IResource): [MenuItem, RouteRecordRaw] => {
    const item = {
      name: res.resKey,
      caption: res.resName,
      path: res.resPath,
      icon: res.icon
    } as MenuItem
    if (!item.path) item.path = '/'
    const routeRecord = {
      name: item.name,
      path: item.path
    } as RouteRecordRaw
    routeRecord.meta = {
      caption: item.caption,
      parents: []
    }
    switch (res.resType) {
      case menuTypes.DIRECTORY:
        routeRecord.component = emptyLayout
        routeRecord.children = []
        routeRecord.component = Empty
        break
      case menuTypes.MENU:
        routeRecord.component = getDynamicComponent(item.path)
        break
    }
    return [item, routeRecord]
  }

  const filterChildren = (pid: string, pMenu: MenuItem, pRouteRecord: RouteRecordRaw) => {
    let childrenMenus = resList.filter((t) => t.parentResId === pid).sort((a, b) => a.sort - b.sort)
    if (childrenMenus.length > 0) {
      let children: MenuItem[] = []
      for (let res of childrenMenus) {
        let [item, routeRecord] = mapRes2MenuItem(res)
        resolveRouteParent(routeRecord, pRouteRecord)
        filterChildren(res.id, item, routeRecord)
        pRouteRecord.children.push(routeRecord)
        children.push(item)
      }
      pMenu.children = children
    }
  }

  const resolveRouteParent = (record: RouteRecordRaw, parent: RouteRecordRaw) => {
    let currentParents = record.meta.parents as string[]
    const parentParents = parent.meta.parents as string[]
    if (parentParents.length > 0) {
      for (const p of parentParents) {
        currentParents.push(p)
      }
    }
    currentParents.push(parent.meta.caption as string)
  }

  for (let res of tops) {
    let [item, routeRecord] = mapRes2MenuItem(res)
    menus.push(item)
    filterChildren(res.id, item, routeRecord)
    dynamicRouters.push(routeRecord)
  }

  dynamicRouters.forEach((routeRecord) => {
    router.addRoute('main', routeRecord)
  })
  return menus
}

const map2Store = (org: IAuthInfo, target: IUserStore) => {
  target.user = {
    id: org.user.id,
    userName: org.user.userName,
    displayName: org.user.realName
  }
  target.roles = [...org.roles]
  target.token = org.token
  target.resources = [...org.resources]
}

export default defineStore({
  id: 'user',
  state: () => {
    const token = loginStore.getToken()
    let data = {
      user: {
        id: '',
        userName: '',
        displayName: ''
      },
      token: token == null ? '' : token,
      roles: [],
      resources: [],
      //标记store是否已经初始化了本地数据
      inited: false
    } as IUserStore
    const user = loginStore.getUserLocal()
    if (user !== null) {
      map2Store(user, data)
      data.inited = true
    }
    return data
  },
  actions: {
    init(authInfo: IAuthInfo, setStore: boolean): void {
      this.user = {
        id: authInfo.user.id,
        userName: authInfo.user.userName,
        displayName: authInfo.user.realName
      }
      this.roles = [...authInfo.roles]
      this.token = authInfo.token
      this.resources = [...authInfo.resources]
      this.inited = true
      if (setStore) {
        loginStore.setUser(authInfo)
      }
    },
    async logout(checkService: boolean) {
      if (checkService !== false) await LoginService.logout()
      menus.splice(0)
      loginStore.clear()
      const store = tabStore()
      store.clear()
    },
    async getMenu(): Promise<MenuItem[]> {
      return new Promise<MenuItem[]>(async (resolve) => {
        if (this.inited == false) {
          var authInfo = await loginStore.getUser()
          this.init(authInfo, false)
        }
        resolve(genMenuTree(this.resources))
      })
    },
    async getAuths(): Promise<string[]> {
      return new Promise<string[]>(async (resolve) => {
        if (this.inited == false) {
          var authInfo = await loginStore.getUser()
          this.init(authInfo, false)
        }
        const auths: string[] = []
        for (const item of this.resources) {
          if (item.resType !== menuTypes.FUNCTION) continue
          auths.push(item.resKey)
        }
        resolve(auths)
      })
    }
  }
})
